#include "dataanalysis.h"

DataAnalysis::DataAnalysis()
{
    _currentEquId = "NOEQUID";
}

DataAnalysis::~DataAnalysis(){
}

void DataAnalysis::onTableChanged(){
    qDebug() << "DataAnalysis触发TableChanged";
    emit tableChanged();
}


QVariantMap DataAnalysis::openLocalAnalysis(QString expId){

    QVariantMap result;
    result["isOpen"] = true;
    QSqlDatabase db = dbHelper::openConnection();
    QSqlQuery query(db);
    QString sql=QString("Select * from ExperimentInfo where ID='%1'").arg(expId);

    QString autosaveName;
    query.exec(sql);
    while (query.next()) {
        autosaveName = query.value("RunTime").toString().remove(":").remove(" ").remove("-");

    }

    QFile file("wlk/"+autosaveName);
    QTextCodec* codec = QTextCodec::codecForName("GBK");
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){
        result["isOpen"] = false;
        return result;
    }

    closeAnalysis("");      // 关闭之前可能存在的数据分析结果

    db.transaction();
    sql="Delete From AmplProgramTemp ";
    query.exec(sql);
    sql="Delete From AmplStepTemp";
    query.exec(sql);
    sql="Delete From ExperimentInfoTemp";
    query.exec(sql);
    sql="Delete From FluorescenceDataTemp";
    query.exec(sql);
    sql="Delete From SampleInfoTemp";
    query.exec(sql);

    QTextStream txtInput(&file);txtInput.setCodec(codec);
    int num=0;
    bool isExpResult=false;
    while (!txtInput.atEnd())
    {
        QString lineStr = txtInput.readLine();

        if(lineStr.contains("FluorescenceDataTemp") && !isExpResult){
            isExpResult = true;
        }
        if(lineStr.contains(".")&&num==0){
            QList<QString> infoList= lineStr.split(',');
            result["EquName"]=infoList[0];
            result["Ip"]=infoList[1];
            result["Port"]=infoList[2];
            result["ExpGuid"]=infoList[3];
            num++;
        }
        else
        {
            query.exec(lineStr);
        }
    }
    qDebug() << "打开文件结果:" << result;

    db.commit();
    closeAnalysis("");          // 从实验数据跳转过来时，清空原有的数据
    openAnalysis("");
    return result;
}


void DataAnalysis::openAnalysis(QString equId){

    if(_states.contains(equId)){
        pState = _states[equId];
    }else{
        _states.insert(equId, new PCRState);
        _states[equId]->init(equId);
        pState = _states[equId];

    }
}

void DataAnalysis::closeAnalysis(QString equId){

    if(!_states.contains(equId)){
        qDebug() << "Warning: No equId" << equId << "analysis";
        return;
    }
    if(_states[equId]){
        delete _states[equId];
        _states[equId] = nullptr;
        _states.remove(equId);
        qDebug() << "Close" << equId << "succeeed";

        QString keys;
        for(auto iter = _states.begin(); iter != _states.end(); iter ++){
            keys += iter.key() + ", ";
        }keys += "ENDING";
        qDebug() << "Current PState List: [" << keys << "]";
    }

}

QVariantMap DataAnalysis::getStandardInfo(){
    QVariantMap res;
    foreach(CHANNEL channel, pState->channelList.keys()){
        QVariantMap r;

        if(!pState->E.contains(channel) || !pState->standardLine.contains(channel)){
            LogHelperJ::write("ERROR: [Class]DataAnalysis [Func]GetStandardInfo - channel not exist - " + QString::number(channel));
            r["E"] = "0.00";
            r["R2"] = "0.99";
            r["K"] = "0.00";
            r["Y"] = "0.00";
            continue;
        }else{
            r["E"] = QString::number(pState->E[channel], 'f', 2);
            r["R2"] = 0.99;
            r["K"] = QString::number(pState->standardLine[channel][0], 'f', 2);
            r["Y"] = QString::number(pState->standardLine[channel][1], 'f', 2);
        }

        res[QString::number(channel)] = r;
    }

    for(int i = 0; i < 4; i ++){
        if(!res.contains(QString::number(i))){
            QVariantMap r;
            r["E"] = "0.00";
            r["R2"] = "0.99";
            r["K"] = "0.00";
            r["Y"] = "0.00";
            res[QString::number(i)] = r;
        }
    }

    return res;
}

QVariantMap DataAnalysis::getAnalysisState(){
    QVariantMap res;
    res["CanAnalysis"] = false;
    res["CanGuide"] = false;

    if(!pState){
        return res;
    }
    res["CanAnalysis"] = pState->canAnalysis;
    res["CanGuide"] = pState->canGuide;

    return res;

}

void DataAnalysis::changeChart(int chartIdx){


    switch (chartIdx) {
    case 0:
        pState->curChart = PCRState::RN;
        break;
    case 1:
        pState->curChart = PCRState::DELTA_RN;
        break;
    case 2:
        pState->curChart = PCRState::LOG_RN;
        break;
    case 3:
        pState->curChart = PCRState::LOG_DELTA_RN;
        break;
    case 4:
        pState->curChart = PCRState::NORM;
        break;
    }
    pState->calculateHalf();

}

void DataAnalysis::changePage(int pageIdx){

    if(!pState){
        return;
    }

    switch (pageIdx) {
    case 0:
        pState->curPage = PCRState::RAW;
        break;
    case 1:
        pState->curPage = PCRState::AMPL;
        break;
    case 2:
        pState->curPage = PCRState::STANDARD;
        break;
    case 3:
        pState->curPage = PCRState::GUIDE;
    }


}

// 前端更改筛选内容 (这是个什么鬼格式……
void DataAnalysis::updateFilter_channel(QVariantList list){
    if(!pState){
        return;
    }
    QVector<int> filterChannel;
    foreach(QVariant vchannel, list){
        filterChannel.push_back(getChannelIdx(vchannel.value<QString>()));
    }
    qDebug() << list;
    foreach(CHANNEL channel, pState->channelList.keys()){
        if(filterChannel.contains(channel)){
            pState->channelList[channel] = true;
        }else{
            pState->channelList[channel] = false;
        }
    }
    pState->updateCurveState();
    qDebug() << pState->channelList;
}
void DataAnalysis::updateFilter_posi(QVariantList list){
    if(!pState){
        return;
    }
    QVector<int> filterPosi;
    foreach(QVariant vposi, list){
        filterPosi.push_back(getPosiIdx(vposi.value<QString>()));
    }
    foreach(POSI posi, pState->posiList.keys()){
        if(filterPosi.contains(posi)){
            pState->posiList[posi] = true;
        }else{
            pState->posiList[posi] = false;
        }
    }
    pState->updateCurveState();
}
void DataAnalysis::updateFilter_name(QVariantList list){
    if(!pState){
        return;
    }
    QVector<QString> filterName;
    foreach(QVariant vname, list){
        filterName.push_back(vname.value<QString>());
    }
    foreach(QString name, pState->nameList.keys()){
        if(filterName.contains(name)){
            pState->nameList[name] = true;
        }else{
            pState->nameList[name] = false;
        }
    }
    pState->updateCurveState();

}
void DataAnalysis::updateFilter_type(QVariantList list){


    if(!pState){
        return;
    }

    qDebug() << "updateFiler_type前" << pState->typeList;
    QVector<QString> filterType;
    foreach(QVariant vtype, list){
        filterType.push_back(vtype.value<QString>());
    }
    foreach(QString type, pState->typeList.keys()){
        if(filterType.contains(type)){
            pState->typeList[type] = true;
        }else{
            pState->typeList[type] = false;
        }
    }
    pState->updateCurveState();
    qDebug() << "updateFiler_type后" << pState->typeList;
}



// 获取Filter列表
QVariantList DataAnalysis::getFilterList_channel(){
    QVariantList list;
    if(!pState){
        return list;
    }
    foreach(CHANNEL channel, pState->channelList.keys()){
        if(pState->channelList[channel]){
            list.push_back(pState->CHANNELLIST[channel]);
        }
    }
    return list;
}
QVariantList DataAnalysis::getFilterList_posi(){
    QVariantList list;
    if(!pState){
        return list;
    }
    foreach(POSI posi, pState->posiList.keys()){
        if(pState->posiList[posi]){
            list.push_back(getPosiName(posi));
        }
    }
    return list;
}
QVariantList DataAnalysis::getFilterList_name(){
    QVariantList list;
    if(!pState){
        return list;
    }
    foreach(QString name, pState->nameList.keys()){
        if(pState->nameList[name]){
            list.push_back(name);
        }
    }
    return list;
}
QVariantList DataAnalysis::getFilterList_type(){
    QVariantList list;
    if(!pState){
        return list;
    }
    foreach(QString type, pState->typeList.keys()){
        if(pState->typeList[type]){
            list.push_back(type);
        }
    }
    return list;
}

// 获取列表
QVariantList DataAnalysis::getList_channel(){
    QVariantList list;
    if(!pState){
        return list;
    }
    foreach(CHANNEL channel, pState->channelList.keys()){
        list.push_back(pState->CHANNELLIST[channel]);
    }
    return list;
}
QVariantList DataAnalysis::getList_posi(){
    QVariantList list;
    if(!pState){
        return list;
    }
    foreach(POSI posi, pState->posiList.keys()){
        list.push_back(getPosiName(posi));
    }
    return list;
}
QVariantList DataAnalysis::getList_name(){
    QVariantList list;
    if(!pState){
        return list;
    }
    foreach(QString name, pState->nameList.keys()){
        list.push_back(name);
    }
    return list;
}
QVariantList DataAnalysis::getList_type(){
    QVariantList list;
    if(!pState){
        return list;
    }
    foreach(QString type, pState->typeList.keys()){
        list.push_back(type);
    }
    return list;
}
void DataAnalysis::setThresholdVisible(bool visible){
    if(!pState){
        return;
    }
    pState->showThr = visible;
}

QVariantList DataAnalysis::getThrPosi(){

    QVariantList res;
    if(!pState){
        return res;
    }

    QMap<CHANNEL, double>   *thrList = nullptr;

    switch(pState->curChart){
    case PCRState::RN:
        thrList = &pState->thrList_Rn;
        break;
    case PCRState::LOG_RN:
        thrList = &pState->thrList_logRn;
        break;
    case PCRState::DELTA_RN:
        thrList = &pState->thrList;
        break;
    case PCRState::LOG_DELTA_RN:
        thrList = &pState->thrList_log;
        break;
    case PCRState::NORM:
        thrList = &pState->thrList_diff;
        break;
    }

    if(thrList){
        foreach(double thr, *thrList){
            res.push_back(thr);
        }
    }
    qDebug() << "获取ThrPosi" << res;
    return res;

}

void DataAnalysis::changeThr(int channel, double value){

    if(!pState){
        return;
    }
    pState->changeThreshold(channel, value);


}


QVariantMap DataAnalysis::getModelConfig(){
    QVariantMap res;
    if(!pState){
        return res;
    }
    res["Func"] = pState->modelFunc;
    res["IR"] = pState->modelIR;
    res["Ct"] = pState->modelCt;
    res["Filter"] = pState->modelFilter;
    return res;
}

void DataAnalysis::setModelConfig(QVariantMap res){
    if(!pState){
        return;
    }

    pState->modelFunc = res["Func"].toInt();
    pState->modelCt = res["Ct"].toInt();
    pState->modelFilter = res["Filter"].toInt();

    pState->calculateAll();

}

QVariantList DataAnalysis::getGuideTable1(){
    QVariantList lists;
    if(!pState){
        return lists;
    }
    int idx = 1;
    for(int i = 0; i < pState->table1Data.size(); i ++){
        QVariantList list;
        list.append(idx);
        int j;
        for(j = 0; j < pState->table1Data[i].size(); j ++){
            list.append(pState->table1Data[i][j]);
        }
        for(; j < 14; j ++){
            list.append("");        // 对空的位置补充数据，防止QML报错
        }

        // 筛选处理
        POSI posi = getPosiIdx(list[1].toString());
        QString name = list[2].toString();
        QString type = list[3].toString();
        CHANNEL channel = getChannelIdx(list[4].toString());

        if(pState->posiList.contains(posi) && pState->posiList[posi] &&
           pState->nameList.contains(name) && pState->nameList[name] &&
           pState->typeList.contains(type) && pState->typeList[type] &&
           pState->channelList.contains(channel) && pState->channelList[channel]){
            lists.push_back(list);
            idx ++;
        }
    }
    return lists;
}

QVariantList DataAnalysis::getGuideTable2(QString type){


    QVariantList lists;
    if(!pState){
        return lists;
    }

    if(type != ""){
        pState->tab2Fil(type);
    }

    int idx = 1;
    for(int i = 0; i < pState->table2Data.size(); i ++){
        QVariantList list;
        list.append(idx);
        int j;
        for(j = 0; j < pState->table2Data[i].size(); j ++){
            list.append(pState->table2Data[i][j]);
        }for(; j < 13; j ++){
            list.append("");        // 对空的位置补充数据，防止QML报错
        }
        if(pState->posiList[getPosiIdx(list[1].toString())] && pState->nameList[list[2].toString()]){
            lists.push_back(list);
            idx ++;
        }

    }
    return lists;
}

QString DataAnalysis::getGuideLabel(QString type){
    QString res = type+": R\xC2\xB2:0.99 Y轴截距:0.00 扩增效率:0.00 斜率:0.00";
    if(!pState || !pState->canAnalysis){
        return res;
    }
    if(type == "AL"){
        if(pState->standardLine.contains(0))
            res = QString("AL: R\xC2\xB2:%1 Y轴截距:%2 扩增效率:%3 斜率:%4").arg("0.99", QString::number(pState->standardLine[0][1], 'f', 2), QString::number(pState->E[0], 'f', 2), QString::number(pState->standardLine[0][0], 'f', 2));
    }else if(type == "Y"){
        if(pState->standardLine.contains(1))
        res = QString("Y: R\xC2\xB2:%1 Y轴截距:%2 扩增效率:%3 斜率:%4").arg("0.99",  QString::number(pState->standardLine[1][1], 'f', 2), QString::number(pState->E[1], 'f', 2), QString::number(pState->standardLine[1][0], 'f', 2));
    }else if(type == "AS"){
        if(pState->standardLine.contains(2))
        res = QString("AS: R\xC2\xB2:%1 Y轴截距:%2 扩增效率:%3 斜率:%4").arg("0.99", QString::number(pState->standardLine[2][1], 'f', 2), QString::number(pState->E[2], 'f', 2), QString::number(pState->standardLine[2][0], 'f', 2));
    }
    return res;
}

QVariantList DataAnalysis::getNum(){

    QVariantList res;
    if(!pState){
        return res;
    }
    auto nums = pState->typeNum();
    foreach(auto r, nums){
        res.push_back(r);
    }
    return res;
}


int DataAnalysis::datao(){
    if(!pState){
        return false;
    }

    QString saveName = pState->experimentName!="" ? pState->experimentName : QDateTime::currentDateTime().toString("yyyy-MM-dd_HH-mm-ss");

    QString filePath = QFileDialog::getSaveFileName(nullptr, "保存", "/path/to/default/"+saveName, "Xlsx files(*.xlsx)");
    if(filePath.isEmpty()|| filePath.isNull()){
        return 2;
    }

    bool res = pState->datao(filePath);
    if(res){
        return 1;
    }else{
        return 0;
    }
}

void DataAnalysis::setColor(QVariantMap colorList){

    if(!pState){
        return;
    }
    pState->colorType = 0;
    foreach(QString key, colorList.keys()){
        CHANNEL channel = getChannelIdx(key);
        if(!pState->channelList.contains(channel)){
            continue;
        }
        pState->colorChannel[channel] = colorList[key].value<QColor>();
    }
}

void DataAnalysis::setColor_posi(QVariantMap colorList){     // Sample到Posi的转换(颜色修改仅针对当前实验……)
    if(!pState){
        return;
    }
    pState->colorType = 1;
    foreach(QString key, colorList.keys()){
        if(!pState->nameList.contains(key)) continue;
        pState->colorName[key] = colorList[key].value<QColor>();
    }
}

int DataAnalysis::exportImage(){



}

int DataAnalysis::getCurrentChart(){
    if(!pState){
        return 0;
    }
    switch(pState->curChart){
    case PCRState::RN:
        return 0;
    case PCRState::DELTA_RN:
        return 1;
    case PCRState::LOG_RN:
        return 2;
    case PCRState::LOG_DELTA_RN:
        return 3;
    case PCRState::NORM:
        return 4;
    }
}

int DataAnalysis::getCurrentPage(){
    if(!pState){
        return 0;
    }
    switch(pState->curPage){
    case PCRState::RAW:
        return 0;
    case PCRState::AMPL:
        return 1;
    case PCRState::STANDARD:
        return 2;
    case PCRState::GUIDE:
        return 3;
    }
    return 0;

}


QVariantList DataAnalysis::getSampleTable(){

    QVariantList result;

    foreach(CURVE curve, pState->curveList.keys()){
        if(!pState->curveList[curve]){ continue; }
        if(!pState->checkCurve(curve)) { continue; }
        
        POSI posi = curve % 100;
        CHANNEL channel = curve / 100;

        QVariantList line;
        line.push_back(getPosiName(posi));
        line.push_back(pState->samplePannel[posi].name);
        line.push_back(pState->samplePannel[posi].type);
        line.push_back(pState->CHANNELLIST[channel]);

        if(pState->Ct.contains(curve))            line.push_back(QString::number(pState->Ct[curve], 'f', 2));
        if(pState->concList.contains(curve))      line.push_back(QString::number(pState->concList[curve], 'f', 4));
        if(pState->avgConcList.contains(channel)) line.push_back(QString::number(pState->avgConcList[channel], 'f', 4));

        result.push_back(line);
    }

    int targetCol = pState->tableSortRule;
    int direct = pState->tableSortDirect;


    // 排序功能性能待优化
/*
    for(int i = 0; i < result.size()-1; i ++){
        for(int j = i+1; j < result.size(); j ++){
            bool isSwap = false;

            if((result[i].value<QVariantList>()).size()<=(targetCol) ||
               (result[j].value<QVariantList>()).size()<=(targetCol)){          // 喵
                continue;
            }

            QString value_i = (result[i].value<QVariantList>())[targetCol].value<QString>();
            QString value_j = (result[j].value<QVariantList>())[targetCol].value<QString>();
            // 比较目标行

            if(targetCol == 0 && value_i.size() != value_j.size() && (value_i.size()!=0&&value_j.size()!=0&&value_i[0]==value_j[0])){       // 处理A11<A2的情况
                if(direct == 0){
                    if(value_i.size() > value_j.size()){
                        isSwap = true;
                    }
                }else{
                    if(value_i.size() < value_j.size()){
                        isSwap = true;
                    }
                }
            }else{
                if(direct == 0){
                    if(value_i > value_j){
                        isSwap = true;
                    }
                }else{
                    if(value_i < value_j){
                        isSwap = true;
                    }
                }
            }

            if(isSwap){
                result.swap(i, j);
            }
        }
    }
    */

    return result;

}



void DataAnalysis::updateSampleTableSelected(QVariantList sampleList){
    pState->boldResult.clear();
    foreach(QVariant info, sampleList){
        QString name = info.value<QString>();
        CHANNEL channel = getChannelIdx(name.split("_")[0]);
        POSI    posi    = getPosiIdx(name.split("_")[1]);
        CURVE   curve   = channel * 100 + posi;
        if(pState->curveList.contains(curve)){
            pState->boldResult.push_back(curve);
        }
    }
}

void DataAnalysis::updateSampleTableSorted(int index){

    if(!pState){
        return;
    }
    if(pState->tableSortRule == index){
        pState->tableSortDirect = pState->tableSortDirect==0 ? 1 : 0;
    }else{
        pState->tableSortRule = index;
    }
}



// 返回值: QMap<曲线名, 曲线信息>
// 曲线信息: QVariantMap: {"IsBold", "Color", "PointList"}
// PointList: QVarintMap: {"x", "y"}

QVariantMap DataAnalysis::getChartData(){

    QVariantMap res;
    if(!pState){
        return res;
    }

    foreach(CURVE curve, pState->curveList.keys()){
        if(!pState->curveList[curve]) { continue; }
        QVariantMap curveInfo;


        curveInfo["Color"] = QColor(188, 188, 188);
        if(pState->colorType == 0){
            int channel = curve / 100;
            if(pState->colorChannel.contains(channel)){
                curveInfo["Color"] = pState->colorChannel[channel];
            }
        }else if(pState->colorType == 1){
            int posi = curve % 100;
            if(pState->samplePannel.contains(posi)) {
                QString name = pState->samplePannel[posi].name;
                if(pState->colorName.contains(name)){
                    curveInfo["Color"] = pState->colorName[name];
                }
            }
        }



        curveInfo["Bold"] = pState->boldResult.contains(curve);

        QVector<QPointF> pointList;

        switch(pState->curPage){

        case PCRState::RAW:
            pointList = pState->modelList[curve]->getRawData();
            break;
        case PCRState::AMPL:
            switch (pState->curChart) {
            case PCRState::RN:
                pointList = pState->modelList[curve]->getFittedData();
                break;
            case PCRState::DELTA_RN:
                pointList = pState->modelList[curve]->getFittedData_delta();
                break;
            case PCRState::LOG_RN:
                pointList = pState->modelList[curve]->getFittedData_log();
                break;
            case PCRState::LOG_DELTA_RN:
                pointList = pState->modelList[curve]->getFittedData_log_delta();
                break;
            case PCRState::NORM:
                pointList = pState->modelList[curve]->getFittedData_diff(pState->rangeIR[curve%100]);
                break;
            }
            break;
        case PCRState::STANDARD:
            pointList = {QPointF(std::log10(pState->concList[curve]), pState->Ct[curve])};
            break;
        default:
            break;
        }


        QVariantList s;
        foreach(QPointF point, pointList){

            if(finite(point.x()) && finite(point.y())){
                QVariantMap p;
                p["x"] = point.x();
                p["y"] = point.y();
                s.push_back(p);
            }
        }
        if(s.size() == 0){
            continue;
        }

        curveInfo["PointList"] = s;

        res[QString::number(curve)] = curveInfo;
    }

    // 标准曲线的那几根线
    if(pState->curPage == PCRState::STANDARD){
        QMap<int, QVector<QPointF>> pointLists = pState->getStandardCurve();
        foreach(int key, pointLists.keys()){
            QVariantMap curveInfo;

            if(!pState->channelList[key]){
                qDebug() << key << "不存在";
                continue;
            }else{
                qDebug() << key << "存在";
            }

            QVector<QPointF> pointList = pointLists[key];
            QVariantList s;
            foreach(QPointF point, pointList){

                if(finite(point.x()) && finite(point.y())){
                    QVariantMap p;
                    p["x"] = point.x();
                    p["y"] = point.y();
                    s.push_back(p);
                }
            }
            if(s.size() == 0){
                continue;
            }

            curveInfo["IsBold"] = false;
            if(key < 1){
                curveInfo["Color"] = QColor(22, 119, 255);
            }else if(key < 2){
                curveInfo["Color"] = QColor(103, 194, 58);
            }else if(key < 3){
                curveInfo["Color"] = QColor(235, 137, 20);
            }else if(key < 4){
                curveInfo["Color"] = QColor(245, 108, 105);
            }
            curveInfo["PointList"] = s;
            res[QString::number(key)] = curveInfo;
        }
    }

    return res;

}
